package org.mashart.pink.m.gui;

//import javax.microedition.lcdui.Alert;
//import javax.microedition.lcdui.AlertType;
//import javax.microedition.lcdui.Command;
//import javax.microedition.lcdui.CommandListener;
//import javax.microedition.lcdui.Display;
//import javax.microedition.lcdui.Displayable;
//import javax.microedition.lcdui.Form;
//import javax.microedition.lcdui.StringItem;
//import javax.microedition.lcdui.game.GameCanvas;

import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.util.Resources;
import com.sun.lwuit.layouts.*;
import com.sun.lwuit.plaf.UIManager;

import java.io.IOException;
import javax.microedition.midlet.MIDletStateChangeException;

import org.mashart.pink.m.PinkrMIDlet;
import org.mashart.pink.m.gps.Receiver;

/**
 * Main UI class that handles user interactions with the application
 */
public class Gui implements ActionListener {
/**
 * TODO It is currently used by Receiver to display debug messages.
 *      Instead, what I'd like to have is kind of a <code>GuiListener</code>
 *      so to separate GUI from the rest of the code
 */

    /**
     * Parent of the Gui: the very MIDlet class instance.
     * Initialized in <code>Gui()</code> constructor.
     */
    private PinkrMIDlet midlet;

    /**
     * Instance of GPS data reciver class.
     * Initialized in <code>Gui()</code> constructor.
     */
    private Receiver recv;

    /**
     * We keep reference to the mobile device display so not to call
     * <code>Display.getDisplay(midlet)</code> every time we need it.
     *
     * Used to display the current <code>Canvas</code> or <code>Form</code>
     * to the user.
     */
//    private Display display;

    /**
     * Used to keep the last debug message and eventually display that
     * to the user
     */
    private TextArea debug;
    /**
     * UTC
     */
    private DigitalMeter utc;
    private DigitalMeter spd;
    private DigitalMeter course;
    private DigitalMeter satellite;

    /**
     * timer during a round
     */
    private DigitalMeter clock;

    /**
     * final time duration of a round
     */
    private Label duration;

    /**
     * distance
     */
    private DigitalMeter dist;

    /**
     * max speed
     */
    private DigitalMeter max_spd;

    /**
     * average speed
     */
    private DigitalMeter ave_spd;

    /**
     * status
     */
    private DigitalMeter status;

    /**
     * Forms
     */
    private Form startedForm;
    private Form stoppedForm;

    /**
     * Compass, used to display the heading course over ground
     */
    private Compass compass;

    /**
     * Tabbed Pane, main interface when running
     */
    private TabbedPane tp;

    /**
     * main UI commands
     */
    private final Command EXIT_CMD = new Command("Exit");
    private final Command PAUSE_CMD = new Command("Pause");
    private final Command RESUME_CMD = new Command("Resume");
    private final Command START_ROUND_CMD = new Command("Start");
    private final Command STOP_ROUND_CMD = new Command("Stop");
    private final Command HIDE_CMD = new Command("Hide");

    static public final int K_UTC = 0;
    static public final int K_SPEED = 1;
    static public final int K_COURSE = 2;
    static public final int K_SATELLITE = 3;
    static public final int K_CLOCK = 4;
    static public final int K_DURATION = 5;
    static public final int K_DIST = 6;
    static public final int K_MAX_SPD = 7;
    static public final int K_AVE_SPD = 8;
    static public final int K_STATUS = 9;

    /**
     * List of available BT devices
     */
//    private final List list = new List("Bluetooth Devices", List.EXCLUSIVE);

    /**
     * Constructor
     */
    public Gui(){
        try {
            Resources r = Resources.open("/PinkrTheme.res");
            UIManager.getInstance().setThemeProps(r.getTheme(r.getThemeResourceNames()[0]));
        } catch ( IOException e ) {
        }
    }

    /**
     * Currently used by GPS data receiver to display current possition,
     * speed and other info
     */
    public void setContent(String frase) {
        debug.setText(frase);
    }

    /**
     * Set the receiver
     */
    public void setReceiver(Receiver recv){
        this.recv = recv;
        this.recv.setGui(this);
    }

    /**
     * Set a field
     */
    public void set( int k, String v ) {
        switch ( k ){
            case K_UTC:
                utc.setText(v);
                break;
            case K_SPEED:
                spd.setText(v);
                break;
            case K_COURSE:
                course.setText(v);
                break;
            case K_SATELLITE:
                satellite.setText(v);
                break;
            case K_CLOCK:
                clock.setText( v );
                break;
            case K_DURATION:
                duration.setText(v);
                break;
            case K_DIST:
                dist.setText(v);
                break;
            case K_MAX_SPD:
                max_spd.setText(v);
                break;
            case K_AVE_SPD:
                ave_spd.setText(v);
                break;
            case K_STATUS:
                status.setText(v);
                break;
        }
    }

    /**
     * Get the compass
     */
    public Compass getCompass () {
        return compass;
    }

    /**
     * Set the midlet
     */
    public void setMidlet(PinkrMIDlet m){
        this.midlet = m;
        Display.init(m);
    }

    /**
     * Shows initial splash screen during initialization
     */
    public void showSplash() {
//        SplashScreen splash = new SplashScreen();
//        display.setCurrent(splash);
    }

    /**
     * Called when a round is started
     * TODO reuse the form object
     */
    public void showStartedConsole(){
        clock = new DigitalMeter("Elapsed Time:");
        debug = new TextArea();
        
        utc = new DigitalMeter("UTC:");
        spd = new DigitalMeter("Speed (km/h):");
        course = new DigitalMeter("Course:");
        satellite = new DigitalMeter("Satellites Fixed:");

        dist = new DigitalMeter("Distance (km):");
        max_spd = new DigitalMeter("Max Speed (km/h):");
        ave_spd = new DigitalMeter("Avg Speed (km/h):");

        status = new DigitalMeter("Status:");

        Container twoColumns = new Container();
        twoColumns.setLayout(new GridLayout(4, 2));
        twoColumns.addComponent(clock);
        twoColumns.addComponent(ave_spd);
        twoColumns.addComponent(course);
        twoColumns.addComponent(spd);
        twoColumns.addComponent(dist);
        twoColumns.addComponent(max_spd);
        twoColumns.addComponent(satellite);
        twoColumns.addComponent(status);

        Container mainContainer = new Container();
        mainContainer.setLayout(new BorderLayout());
        mainContainer.setScrollableY(true);
        mainContainer.addComponent(BorderLayout.NORTH, utc);
        mainContainer.addComponent(BorderLayout.CENTER, twoColumns);

        compass = new Compass();

        Container compassContainer = new Container();
//        compassContainer.setLayout(new BorderLayout());
//        compassContainer.addComponent(BorderLayout.CENTER, compass);
        compassContainer.addComponent(compass);

        tp = new TabbedPane( TabbedPane.TOP );
        tp.addTab( "Digital", mainContainer );
        tp.addTab("Compass", compassContainer);

        startedForm = new Form();
//        startedForm.setScrollable(true);
        startedForm.setLayout(new BorderLayout());
        startedForm.addComponent(BorderLayout.CENTER, tp);
        startedForm.addCommand(PAUSE_CMD);
        startedForm.addCommand(HIDE_CMD);
        startedForm.addCommandListener(this);
        startedForm.show();
    }

    /**
     * Called after a round stopped
     */
    public void showStoppedConsole(){
        duration = new Label();
        duration.setText("Duration: " + recv.getRuntime());
        
        stoppedForm = new Form();
        stoppedForm.addComponent(duration);
        stoppedForm.addCommand(START_ROUND_CMD);
        stoppedForm.addCommand(EXIT_CMD);
        stoppedForm.addCommandListener(this);
        stoppedForm.show();
    }

    /**
     * start a round
     */
    public void startRound(){
        new Thread(){
            public void run(){
                midlet.startRound();
            }
        }.start();
        showStartedConsole();
//            midlet.startRound();
        startedForm.removeCommand(RESUME_CMD);
        startedForm.removeCommand(STOP_ROUND_CMD);
        startedForm.addCommand(PAUSE_CMD);
        startedForm.addCommand(HIDE_CMD);
        set(K_STATUS, "Running");
    }

    /**
     * pause a round
     */
    public void pauseRound(){
        new Thread(){
            public void run(){
                midlet.pauseRound();
            }
        }.start();
        startedForm.removeCommand(PAUSE_CMD);
        startedForm.removeCommand(HIDE_CMD);
        startedForm.addCommand(RESUME_CMD);
        startedForm.addCommand(STOP_ROUND_CMD);
        set(K_STATUS, "Paused");
    }

    /**
     * resume a round
     */
    public void resumeRound(){
        new Thread(){
            public void run(){
                midlet.resumeRound();
            }
        }.start();
        startedForm.removeCommand(RESUME_CMD);
        startedForm.removeCommand(STOP_ROUND_CMD);
        startedForm.addCommand(PAUSE_CMD);
        startedForm.addCommand(HIDE_CMD);
        set(K_STATUS, "Running");
    }

    /**
     * stop a round
     */
    public void stopRound(){
        new Thread(){
            public void run(){
                midlet.stopRound();
            }
        }.start();
        showStoppedConsole();
    }

    /**
     * Hide the app windows and keep running at background.
     * Tested under Symbian S60. May not work on some other operating system.
     */
    public void hide(){
//        display.setCurrent(null);
    }

    /**
     * Method called by other parts of the code to show some information
     */
    public void showInfo(String msg, int timeout) {
        Dialog.show("Info", msg, Dialog.TYPE_INFO, null, "OK", "Cancel", timeout);
    }

    /**
     * Method called by other parts of the code when something
     * went wrong
     */
    public void showError(String msg) {
        Dialog.show("Error", msg, Dialog.TYPE_ERROR, null, "OK", "Cancel", 0);
    }

    /**
     * Listens and acts on commands
     */
    public void actionPerformed ( ActionEvent ae ) {
        Command c = ae.getCommand();
        if(c == START_ROUND_CMD){
            startRound();
        }
        else if(c == PAUSE_CMD){
            pauseRound();
        }
        else if(c == RESUME_CMD){
            resumeRound();
        }
        else if(c == STOP_ROUND_CMD){
            stopRound();
        }
        else if(c == HIDE_CMD){
            hide();
        }
        else if (c == EXIT_CMD) {
            try{
                // terminate
                midlet.terminate();
                // exit midlet
                midlet.destroyApp(true);
                midlet.notifyDestroyed();
            }catch(MIDletStateChangeException e){
                showError(e.getMessage());
            }
        }
    }
}
